package zdream.pmfield.stage.effect;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

import zdream.pmfield.data.foe.Ability;
import zdream.pmfield.data.foe.MoveAdditionalEffects;
import zdream.pmfield.stage.buff.foe.FoeStageBuff;
import zdream.pmfield.stage.buff.StageBuff;
import zdream.pmfield.stage.director.HookStore;
import zdream.pmfield.stage.director.HookType;
import zdream.pmfield.stage.director.Hooks;
import zdream.pmfield.stage.message.FoeAddBuffMessage;
import zdream.pmfield.stage.object.FoeActor;

import static zdream.pmfield.data.foe.MoveAdditionalEffects.E_APPLY_BUFF;

/**
 * @author Zdream
 * @date 2023-12-09
 * @since 0.0.1
 */
public class ApplyBuffEffect extends AbstractEffect {
	private static final String DESC_KEY_BUFF = MoveAdditionalEffects.K_APPLY_BUFF_BUFF;
	private static final String DESC_KEY_TARGET = MoveAdditionalEffects.K_APPLY_BUFF_TARGET;
	private static final String DESC_KEY_PROPERTIES = MoveAdditionalEffects.K_APPLY_BUFF_PROPERTIES;

	private final String buffCategory;
	private final String[] buffProperties;
	public final EffectTarget target;
	private final Ability ability;

	public ApplyBuffEffect(MoveAdditionalEffects.EffectDescription description) {
		super(E_APPLY_BUFF);

		final Map<String, ?> parsed = MoveAdditionalEffects.parse(description);
		Objects.requireNonNull(parsed);
		buffCategory = (String) parsed.get(DESC_KEY_BUFF);
		buffProperties = (String[]) parsed.get(DESC_KEY_PROPERTIES);
		target = EffectTarget.valueOf((String) parsed.get(DESC_KEY_TARGET));
		ability = description.ability;
	}

	@Override
	public void init(Function<HookType, HookStore.HookHandlerBuilder> onHook) {
		onHook.apply(HookType.AFTER_EXECUTE_ATTACK)
				.handle(this::applyBuffAfterAttack)
				.buildAndSave();
		onHook.apply(HookType.ON_CREATE_BUFF_BY_ABILITY)
				.handle(this::applyBuffForAbility)
				.buildAndSave();
	}

	private void applyBuffAfterAttack(Hooks.HookContext rawContext) {
		Hooks.AttackHookContext hooks = rawContext.as();
		List<FoeActor> foes = affectedFoesWithTarget(hooks.attackContext, target);
		for (FoeActor foe : foes) {
			final FoeStageBuff buff = createFoeBuff(foe);
			final FoeActor.ReceiveBuffReport report = foe.receiveBuff(buff);
			pushMessage(foe.stage, new FoeAddBuffMessage(report));
		}
	}

	private void applyBuffForAbility(Hooks.HookContext rawContext) {
		Hooks.FoeBuffContext hooks = rawContext.as();
		if (target != EffectTarget.self) {
			throw new IllegalArgumentException("尚未支持 target 为 " + target + " 的操作");
		}

		final FoeActor foe = hooks.foe;
		final FoeStageBuff buff = createFoeBuff(foe);
		final FoeActor.ReceiveBuffReport report = foe.receiveBuff(buff);
		pushMessage(foe.stage, new FoeAddBuffMessage(report));
	}

	private FoeStageBuff createFoeBuff(FoeActor foe) {
		return (FoeStageBuff) foe.stage.director.buffs.createBuff(
				new StageBuff.BuffDescription(buffCategory)
						.withFoe(foe)
						.withProperties(buffProperties)
						.withAbility(ability)
		);
	}
}
